﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using System.Xml;
using System.Collections.Generic;
using System.Threading;

using SangoBang;
using SangoBang.Cards;
using System.Text;

/// <summary>
/// Summary description for EventController
/// </summary>
/// 
namespace SangoBang
{
    public class EventController
    {
        public EventController()
        {
            //
            // TODO: Add constructor logic here
            //
        }
        public string OnReceiveMsg(String msg, String session_guid)
        {
           
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(msg);
            XmlElement root = doc.DocumentElement;
            string type = root.GetAttribute("type");
            Player sender = null;
            Player receiver = null;
            switch (type)
            {
                case "newuser":
                    string displayName = root.FirstChild.InnerText;
                    if (this.mGame.GetPlayer(displayName) != null)
                            return "<message type=\"joinResult\" result=\"fail\"><detail>UsedPlayerName</detail></message>";
                    Guid guid = Guid.NewGuid();
                    Player player = new Player(displayName);
                    player.Guid = guid.ToString();
                    mGame.AddPlayer(player);
                    mplayerDict.Add(guid.ToString(), player);
                    string isHost = "false";
                    if (mplayerDict.Count == 1)
                    {
                        isHost = "true";
                    }
                    this.RefreshPlayerList();
                    return "<message type=\"joinResult\" result=\"success\" ishost=\""+isHost+"\"><guid>" + guid.ToString() + "</guid></message>";

                case "userLeave":
                    return UserLeave(session_guid);
                case "startGame":
                    mGame.StartGame();
                    DispatchRoleCards();
                    DispatchCharacterCards();
                    DispatchGameCards();
                    DispatchCardFinish();
                    Player reporter = mplayerDict[session_guid];
                    ReportAction(reporter);
                    return "";
                case "getGameCard":
                    string ret = this.GetGameCard(root);
                    return ret;
                case "discard":
                    sender = mplayerDict[session_guid];
                    DisGameCard(root, sender);
                    return "";

                case "playerAction":                    
                    sender = mplayerDict[session_guid];
                    XmlAttribute target = root.ChildNodes[0].Attributes["target"];
                    if (target != null)
                    { 
                        receiver = mGame.GetPlayer(target.Value);
                    }
                   
                    string actionType = root.ChildNodes[0].Attributes["type"].Value;
                    Action action = ActionFactory.GetAction(actionType, sender, receiver);
                    if (action != null)
                    {
                        return action.Do();
                    }
                    else
                    {
                        return string.Empty;
                    }
                

                case "playerActionFinish":
                    sender = mplayerDict[session_guid];
                    
                    Player reporterNext = sender.Next;
                    ReportAction(reporterNext);
                    return string.Empty;

                default:
                    return "<message type=\"unkown\"/>";

            }
            
        }

        private string UserLeave(String session_guid)
        {
            Player player = mplayerDict[session_guid];
            lock (player.MessageQueue)
            {
                player.MessageQueue.Enqueue("<message type=\"userLeaveResult\" result=\"success\"/>");
            }
            player.MessageEvent.Set();

            mGame.RemovePlayer(player);
            mplayerDict.Remove(session_guid);
            this.RefreshPlayerList();
            return "";
        }

        private string GetGameCard(XmlElement msgElement)
        {
            int number = Convert.ToInt32(msgElement.GetAttribute("number"));
            string msg = "<message type=\"gameCard\">";
            for (int i = 0; i < number; i++) 
            {
                msg += "<gameCard>kill</gameCard>"; 
            }
            msg += "</message>";
            return msg;
        }

        private string DisGameCard(XmlElement root,Player sender)
        {
            int count = root.ChildNodes.Count;
            for (int i = 0; i < count; i++)
            {
                --sender.CardNumber;
            }
            UpdatePlayer(sender);
            return "";
        }

        private void DispatchCardFinish()
        {
            string msg = "<message type=\"dispatchCardFinish\"/>";
            foreach (var player in mGame.mPlayerList)
            {
                lock (player.MessageQueue)
                {
                    player.MessageQueue.Enqueue(msg);
                }
                player.MessageEvent.Set();
            }

        }
        private void DispatchGameCards() 
        {  
            foreach (var player in mGame.mPlayerList)
            {
                String msg = "<message type=\"gameCard\">";
                for (int i = 0; i < 4; i++) 
                {
                    GameCard gamecard = mGame.GetGameCard();
                    msg += "<gameCard>" + gamecard.ToString()+"</gameCard>";
                }
                msg += "</message>";
                lock (player.MessageQueue)
                {
                    player.MessageQueue.Enqueue(msg);
                }
                player.MessageEvent.Set();
            }
        }
        private void DispatchGameCards(Player player)
        {
            String msg = "<message type=\"gameCard\">";
            for (int i = 0; i < 2; i++)
            {
                GameCard gamecard = mGame.GetGameCard();
                msg += "<gameCard>" + gamecard.ToString() + "</gameCard>";
            }
            msg += "</message>";
            player.CardNumber += 2;
            lock (player.MessageQueue)
            {
                player.MessageQueue.Enqueue(msg);
            }
            player.MessageEvent.Set();           
        }

        private void DispatchCharacterCards()
        {
            string msg = "<message type=\"characterCard\">";
            foreach (var player in mGame.mPlayerList)
            {
                string name = player.mName;
                string character = player.mCharacterName;
                string hptext = player.mCharacter.mHitPoint.ToString();
                string description = "Luck Aura";
                msg += "<character player=\"" + name + "\" hp=\"" + hptext 
                    + "\" description =\"" + description + "\">" + character + "</character>";
             }   
             msg += "</message>";
             foreach (var player in mGame.mPlayerList)
             {
                 lock (player.MessageQueue)
                 {
                     player.MessageQueue.Enqueue(msg);
                 }
                 player.MessageEvent.Set();
             }
            
        }
        private void DispatchRoleCards() 
        {
            string msg;
            string zhugongMsg ="";
            foreach (var player in mGame.mPlayerList)
            {
                msg = "<message type=\"roleCard\">";
                string role = player.mRole;
                msg += "<role>" + role + "</role></message>";
                if (role == "P Zhugong")
                {
                    zhugongMsg = "<message type=\"playerRole\"><role player=\"" +
                        player.mName + "\">" + role + "</role></message>";
                }
                lock (player.MessageQueue)
                {
                    player.MessageQueue.Enqueue(msg);
                }
                player.MessageEvent.Set();
            }
            foreach (var player in mGame.mPlayerList)
            {
                string role = player.mRole;
                if (role == "P Zhugong") continue;
                lock (player.MessageQueue)
                {
                    player.MessageQueue.Enqueue(zhugongMsg);
                }
                player.MessageEvent.Set();
            }
            

        }

        private void UpdatePlayer(Player sender)
        {
            
            StringBuilder rtnMsg2 = new StringBuilder(512);
            rtnMsg2.Append("<message type=\"playerUpdate\"><playerStatus player=\"");
            rtnMsg2.Append(sender.mName);
            rtnMsg2.Append("\" cardNumber=\"");
            rtnMsg2.Append(sender.CardNumber);
            rtnMsg2.Append("\" life=\"");
            rtnMsg2.Append(sender.HP);
            rtnMsg2.Append("\"></playerStatus></message>");

            foreach (Player player in mGame.mPlayerList)
            {
                lock (player.MessageQueue)
                {
                    player.MessageQueue.Enqueue(rtnMsg2.ToString());
                }
                player.MessageEvent.Set();
            }
        }


        private void ReportAction(Player sender)
        {
            string reportMsg = "<message type=\"playerActionStart\" player=\"" + sender.mName + "\"/>";
            foreach (Player player in mGame.mPlayerList)
            {
                lock (player.MessageQueue)
                {
                    player.MessageQueue.Enqueue(reportMsg);
                }
                player.MessageEvent.Set();
            }

            DispatchGameCards(sender);
            UpdatePlayer(sender);
        }

        private Dictionary<String, Player> mplayerDict = new Dictionary<String, Player>();
        private void RefreshPlayerList()
        {
            string msg = "<message type=\"playerList\">";
            lock (mGame.mPlayerList)
            {
                foreach (var player in mGame.mPlayerList)
                {
                    msg += "<player>" + player.mName + "</player>";
                }
                msg += "</message>";
                foreach (var player in mGame.mPlayerList)
                {
                    lock (player.MessageQueue)
                    {
                        player.MessageQueue.Enqueue(msg);
                    }
                    player.MessageEvent.Set();
                }
            }
        }
        public string GetMsg(String guid)
        {
            if (!mplayerDict.ContainsKey(guid) )
            {
                return "<message type=\"invalidGuid\"/>";
            }
            Player player = mplayerDict[guid];
            String msg;
            if (player.MessageQueue.Count == 0)
            {
                player.MessageEvent.WaitOne(20000, false);
            }
            if (player.MessageQueue.Count == 0)
            {
                return "<message type=\"empty\"/>";
            }
            lock (player.MessageQueue)
            {
                msg = player.MessageQueue.Dequeue();
            }
            return msg;

        }

        Game mGame = new Game();

    }
}
